import { Repository } from 'typeorm';
import { AppDataSource } from '../../config/database';
import { AdminUser } from '../../entities/AdminUser';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { JWT_SECRET } from '../../middleware/auth';
import authConfig from '../../config/auth';
import logger from '../../utils/logger';

export interface AdminUserInfo {
    id: number;
    username?: string;
    nickname?: string | null;
    avatar?: string | null;
    status?: number;
    token?: string;
}

export class AdminUserService {
    private userRepository: Repository<AdminUser>;

    constructor() {
        this.userRepository = AppDataSource.getRepository(AdminUser);
    }

    async findAll(query: any = {}): Promise<{ users: AdminUser[]; total: number }> {
        const { page = 1, pageSize = 10, ...whereQuery } = query;

        const [users, total] = await this.userRepository.findAndCount({
            where: whereQuery,
            order: { id: 'DESC' },
            skip: (page - 1) * pageSize,
            take: pageSize,
            select: ['id', 'username', 'nickname', 'avatar', 'status', 'createdBy', 'updatedBy', 'createTime', 'updatedTime']
        });

        return { users, total };
    }

    async findById(id: number): Promise<AdminUser | null> {
        return await this.userRepository.findOne({
            where: { id },
            select: ['id', 'username', 'nickname', 'avatar', 'status', 'createdBy', 'updatedBy', 'createTime', 'updatedTime']
        });
    }

    async findByUsername(username: string): Promise<AdminUser | null> {
        return await this.userRepository.findOne({
            where: { username }
        });
    }

    async create(userData: Partial<AdminUser>): Promise<AdminUser> {
        const existingUser = await this.userRepository.findOne({
            where: { username: userData.username }
        });

        if (existingUser) {
            throw { status: 400, message: '用户名已存在' };
        }

        if (userData.password) {
            userData.password = await this.hashPassword(userData.password);
        }

        userData.createTime = new Date();
        userData.updatedTime = new Date();
        
        const savedUser = await this.userRepository.save(userData);
        const { password, ...userWithoutPassword } = savedUser;
        return userWithoutPassword as AdminUser;
    }

    async update(id: number, updateData: Partial<AdminUser>): Promise<AdminUser | null> {
        const user = await this.findById(id);
        if (!user) {
            return null;
        }

        if (updateData.password) {
            updateData.password = await this.hashPassword(updateData.password);
        }

        await this.userRepository.update(id, updateData);
        return await this.findById(id);
    }

    async delete(id: number): Promise<boolean> {
        const result = await this.userRepository.delete(id);
        return result.affected ? result.affected > 0 : false;
    }

    async hashPassword(password: string): Promise<string> {
        return await bcrypt.hash(password, authConfig.SALT_STR);
    }

    async verifyPassword(plainPassword: string, hashedPassword: string): Promise<boolean> {
        return await bcrypt.compare(plainPassword, hashedPassword);
    }

    async login(username: string, password: string, captcha?: string, session?: any): Promise<AdminUser | null> {
        const user = await this.userRepository.findOne({
            where: { username }
        });

        if (!user || !user.password) {
            return null;
        }

        if (user.status !== 1) {
            logger.warn(`用户 ${username} 尝试登录，但状态异常: ${user.status}`);
            throw new Error('该用户状态不正确，请联系管理员！');
        }

        const isPasswordValid = await this.verifyPassword(password, user.password);
        if (!isPasswordValid) {
            return null;
        }

        const { password: _, ...userWithoutPassword } = user;
        return userWithoutPassword as AdminUser;
    }

    async updateLoginInfo(userId: number, ip?: string): Promise<void> {
        await this.userRepository.update(userId, {
            updatedTime: new Date()
        });
    }

    async changePassword(id: number, oldPassword: string, newPassword: string): Promise<boolean> {
        const user = await this.userRepository.findOne({
            where: { id }
        });

        if (!user || !user.password) {
            return false;
        }

        const isPasswordValid = await this.verifyPassword(oldPassword, user.password);
        if (!isPasswordValid) {
            return false;
        }

        const hashedNewPassword = await this.hashPassword(newPassword);
        await this.userRepository.update(id, { password: hashedNewPassword });
        return true;
    }

    generateToken(user: Partial<AdminUser>, roleInfo?: any): string {
        return jwt.sign(
            {
                id: user.id,
                username: user.username,
                nickname: user.nickname,
                permissions: roleInfo?.permissions || []
            },
            JWT_SECRET,
            { expiresIn: '24h' }
        );
    }

    // 转换为用户信息对象，类似于 auth 中的 toUserInfo 方法
    toUserInfo(user: Partial<AdminUser>): AdminUserInfo {
        return {
            id: user.id!,
            username: user.username,
            nickname: user.nickname || '',
            avatar: user.avatar || '',
            status: user.status
        };
    }

    async getUserWithPermissions(userId: number): Promise<any> {
        const user = await this.userRepository.findOne({
            where: { id: userId },
            select: ['id', 'username', 'nickname', 'avatar', 'status']
        });

        if (!user) {
            return null;
        }

        return {
            ...user,
            permissions: []
        };
    }

    async checkUserStatus(user: AdminUser): Promise<{ valid: boolean; message?: string }> {
        if (user.status !== 1) {
            return { valid: false, message: '账号已被禁用，请联系管理员' };
        }
        return { valid: true };
    }

    async enableUser(userId: number): Promise<boolean> {
        const result = await this.userRepository.update(userId, { status: 1 });
        return result.affected ? result.affected > 0 : false;
    }

    async disableUser(userId: number): Promise<boolean> {
        const result = await this.userRepository.update(userId, { status: 0 });
        return result.affected ? result.affected > 0 : false;
    }
}

export const adminUserService = new AdminUserService(); 